/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Global Trust Authority is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

use std::future::Future;
use std::pin::Pin;

use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
use base64::engine::general_purpose::STANDARD;
use common_log::error;
use openssl::sha::Sha256;

use crate::{
    chain::attestation_chain::{AttestationHandler, AttestationContext},
    error::attestation_error::AttestationError,
};

/// Handler for processing nonce in the attestation chain
pub struct NonceProcessingHandler {
    next: Option<Box<dyn AttestationHandler>>,
}

impl NonceProcessingHandler {
    pub fn new() -> Self {
        Self { next: None }
    }

    /// Validate nonce type
    fn validate_nonce_type(&self, nonce_type: &str) -> Result<(), AttestationError> {
        match nonce_type {
            "user" | "verifier" | "ignore" => Ok(()),
            _ => {
                error!("Invalid nonce_type: {}", nonce_type);
                Err(AttestationError::NonceVerificationError(format!("invalid nonce_type: {}", nonce_type)))
            }
        }
    }

    /// Decode base64 nonce string to bytes
    fn decode_nonce(&self, nonce: &str) -> Result<Vec<u8>, AttestationError> {
        BASE64.decode(nonce).map_err(|e| {
            error!("Failed to decode nonce: {}", e);
            AttestationError::NonceVerificationError(format!("failed to decode nonce: {}", e))
        })
    }

    /// Process nonce for user or verifier types
    fn process_required_nonce(&self, nonce: Option<&String>) -> Result<Vec<u8>, AttestationError> {
        match nonce {
            Some(n) => self.decode_nonce(n),
            None => {
                error!("Missing nonce");
                Err(AttestationError::NonceVerificationError("missing nonce".into()))
            }
        }
    }

    /// Get nonce bytes from nonce string based on nonce type
    fn get_nonce_bytes(&self, nonce_type: &str, nonce: Option<&String>) -> Result<Option<Vec<u8>>, AttestationError> {
        self.validate_nonce_type(nonce_type)?;
        
        match nonce_type {
            "user" | "verifier" => {
                let bytes = self.process_required_nonce(nonce)?;
                Ok(Some(bytes))
            },
            "ignore" => Ok(None),
            _ => unreachable!(), // This case is already handled by validate_nonce_type
        }
    }

    /// Generate aggregate nonce bytes from nonce and attester data
    fn get_aggregate_nonce_bytes(
        &self,
        nonce: &Option<Vec<u8>>,
        attester_data: &Option<serde_json::Value>,
    ) -> Option<Vec<u8>> {
        // If both inputs are None, return None
        if attester_data.is_none() && nonce.is_none() {
            return None;
        }

        // Create a new SHA-256 hasher
        let mut hasher = Sha256::new();

        // Update with nonce if it exists
        if let Some(nonce) = nonce {
            hasher.update(nonce);
        }

        // Update with attester_data if it exists
        if let Some(data) = attester_data {
            // Convert to string and then to bytes
            let data_str = data.to_string();
            // Base64 encode the string
            let base64_data = STANDARD.encode(&data_str);
            hasher.update(base64_data.as_bytes());
        }

        let result = hasher.finish();
        Some(result.to_vec())
    }
}

impl AttestationHandler for NonceProcessingHandler {
    fn handle<'a>(&'a self, context: &'a mut AttestationContext) -> Pin<Box<dyn Future<Output = Result<(), AttestationError>> + Send + 'a>> {
        Box::pin(async move {
            let nonce_type = context.measurement.nonce_type.as_ref().map_or("verifier", |s| s);
            let nonce_bytes = self.get_nonce_bytes(nonce_type, context.measurement.nonce.as_ref())?;
            context.nonce_bytes = nonce_bytes;
            
            // Generate aggregate nonce
            let aggregate_nonce_bytes = self.get_aggregate_nonce_bytes(
                &context.nonce_bytes,
                &context.measurement.attester_data,
            );
            context.aggregate_nonce_bytes = aggregate_nonce_bytes;
            
            Ok(())
        })
    }
    
    fn set_next(&mut self, next: Box<dyn AttestationHandler>) {
        self.next = Some(next);
    }
    
    fn get_next(&self) -> Option<&dyn AttestationHandler> {
        self.next.as_ref().map(|h| h.as_ref())
    }
    
    fn name(&self) -> &'static str {
        "NonceProcessing"
    }
}